#include <iostream>
#include <memory>

class Investment {
public:
    Investment() { std::cout << "Investment::Investment()" << std::endl; }
    virtual ~Investment() { std::cout << "Investment::~Investment()" << std::endl; }
};

class Bond : public Investment{
public:
    Bond(int) { std::cout << "Bond::Bond(int)" << std::endl; }
    virtual ~Bond() override final { std::cout << "Bond::~Bond()" << std::endl; }
};

class Stock : public Investment{
public:
    Stock(int, int) { std::cout << "Stock::Stock(int, int)" << std::endl; }
    virtual ~Stock() override final { std::cout << "Stock::~Stock()" << std::endl; }
};

template<typename... T>
Investment* MakeInvestment(T&&... params)
{
    constexpr uint32_t sizeofParams = sizeof...(params);
    if constexpr (sizeofParams == 1) { return new Bond(std::forward<T>(params)...); }
    if constexpr (sizeofParams == 2) { return new Stock(std::forward<T>(params)...); }
    return nullptr;
}

template<typename... T>
std::unique_ptr<Investment> MakeInvestment1(T&&... params)
{
    constexpr uint32_t sizeofParams = sizeof...(params);
    if constexpr (sizeofParams == 1) { return std::unique_ptr<Investment>(new Bond(std::forward<T>(params)...)); }
    if constexpr (sizeofParams == 2) { return std::unique_ptr<Investment>(new Stock(std::forward<T>(params)...)); }
    return nullptr;
}

int main() {
    {
        class Test {
            uint32_t ui;
        public:
            Test() { std::cout << "Test::Test()" << std::endl; }
            ~Test() { std::cout << "Test::~Test()" << std::endl; }
        };

        std::cout << sizeof(Test*) << ", " << sizeof(std::unique_ptr<Test>) << std::endl;

        std::unique_ptr<Test> t(new Test);

        std::unique_ptr<Test> t1 = std::move(t);
        std::unique_ptr<Test> t2 = std::move(t1);
    }

    {
        Investment* investment = MakeInvestment(1, 1);
        delete investment;

        auto investment1 = MakeInvestment1(1);
    }

    {
        auto deletor = [](Investment* i) {
            std::cout << "investment unique_ptr deletor" << std::endl;
            delete i;
        };

        std::unique_ptr<Investment, decltype(deletor)> investment(new Bond(1), deletor);
    }

    return 0;
}